// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_
#define CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_

#include <memory>

#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/loader/resource_controller.h"
#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "content/browser/ssl/ssl_error_handler.h"
#include "content/common/content_export.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"

#ifdef TENCENT_CHANGES
#include "tencent/build/config_net.h"
#endif

namespace net {
class X509Certificate;
}

namespace content {
class ResourceDispatcherHostLoginDelegate;
class ResourceHandler;
class ResourceLoaderDelegate;
class ResourceRequestInfoImpl;

// This class is responsible for driving the URLRequest (i.e., calling Start,
// Read, and servicing events).  It has a ResourceHandler, which is typically a
// chain of ResourceHandlers, and is the ResourceController for its handler.
class CONTENT_EXPORT ResourceLoader : public net::URLRequest::Delegate,
                                      public SSLErrorHandler::Delegate,
                                      public SSLClientAuthHandler::Delegate,
                                      public ResourceController {
public:
#if ENABLE_TENCENT(NETWORK_REFACTOR)
    class CONTENT_EXPORT PrefetchDelegate {
    public:
        virtual void OnPrefetchStarted() = 0;
        virtual void OnPrefetchDestoryed() = 0;
        virtual void OnPrefetchNavigated() = 0;
    };
#endif

    ResourceLoader(std::unique_ptr<net::URLRequest> request,
        std::unique_ptr<ResourceHandler> handler,
        ResourceLoaderDelegate* delegate);
    ~ResourceLoader() override;

    void StartRequest();
    void CancelRequest(bool from_renderer);

    bool is_transferring() const { return is_transferring_; }
    void MarkAsTransferring(const base::Closure& on_transfer_complete_callback);
    void CompleteTransfer();

    net::URLRequest* request() { return request_.get(); }
    ResourceRequestInfoImpl* GetRequestInfo();

    void ClearLoginDelegate();

private:
    // net::URLRequest::Delegate implementation:
    void OnReceivedRedirect(net::URLRequest* request,
        const net::RedirectInfo& redirect_info,
        bool* defer) override;
    void OnAuthRequired(net::URLRequest* request,
        net::AuthChallengeInfo* info) override;
    void OnCertificateRequested(net::URLRequest* request,
        net::SSLCertRequestInfo* info) override;
    void OnSSLCertificateError(net::URLRequest* request,
        const net::SSLInfo& info,
        bool fatal) override;
    void OnResponseStarted(net::URLRequest* request) override;
    void OnReadCompleted(net::URLRequest* request, int bytes_read) override;

    // SSLErrorHandler::Delegate implementation:
    void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override;
    void ContinueSSLRequest() override;

    // SSLClientAuthHandler::Delegate implementation.
    void ContinueWithCertificate(net::X509Certificate* cert) override;
    void CancelCertificateSelection() override;

    // ResourceController implementation:
    void Resume() override;
    void Cancel() override;
    void CancelAndIgnore() override;
    void CancelWithError(int error_code) override;

    void StartRequestInternal();
    void CancelRequestInternal(int error, bool from_renderer);
    void FollowDeferredRedirectInternal();
    void CompleteResponseStarted();
    void ReadMore(bool is_continuation);
    void ResumeReading();
    // Passes a read result to the handler.
    void CompleteRead(int bytes_read);
    void ResponseCompleted();
    void CallDidFinishLoading();
    void RecordHistograms();

    bool is_deferred() const { return deferred_stage_ != DEFERRED_NONE; }

    // Used for categorizing loading of prefetches for reporting in histograms.
    // NOTE: This enumeration is used in histograms, so please do not add entries
    // in the middle.
    enum PrefetchStatus {
        STATUS_UNDEFINED,
        STATUS_SUCCESS_FROM_CACHE,
        STATUS_SUCCESS_FROM_NETWORK,
        STATUS_CANCELED,
        STATUS_SUCCESS_ALREADY_PREFETCHED,
        STATUS_MAX,
    };

    enum DeferredStage {
        DEFERRED_NONE,
        DEFERRED_START,
        DEFERRED_REDIRECT,
        DEFERRED_READ,
        DEFERRED_RESPONSE_COMPLETE,
        DEFERRED_FINISH
    };
    DeferredStage deferred_stage_;

    std::unique_ptr<net::URLRequest> request_;
    std::unique_ptr<ResourceHandler> handler_;
    ResourceLoaderDelegate* delegate_;

    scoped_refptr<ResourceDispatcherHostLoginDelegate> login_delegate_;
    std::unique_ptr<SSLClientAuthHandler> ssl_client_auth_handler_;

    base::TimeTicks read_deferral_start_time_;

    // Indicates that we are in a state of being transferred to a new downstream
    // consumer.  We are waiting for a notification to complete the transfer, at
    // which point we'll receive a new ResourceHandler.
    bool is_transferring_;

    // Called when a navigation has finished transfer.
    base::Closure on_transfer_complete_callback_;

    // Instrumentation add to investigate http://crbug.com/503306.
    // TODO(mmenke): Remove once bug is fixed.
    int times_cancelled_before_request_start_;
    bool started_request_;
    int times_cancelled_after_request_start_;

    // Stores the URL from a deferred redirect.
    GURL deferred_redirect_url_;

    base::WeakPtrFactory<ResourceLoader> weak_ptr_factory_;

    DISALLOW_COPY_AND_ASSIGN(ResourceLoader);
};

} // namespace content

#endif // CONTENT_BROWSER_LOADER_RESOURCE_LOADER_H_
